/*
*  Copyright 2019-2020 Zheng Jie
*
*  Licensed under the Apache License, Version 2.0 (the "License");
*  you may not use this file except in compliance with the License.
*  You may obtain a copy of the License at
*
*  http://www.apache.org/licenses/LICENSE-2.0
*
*  Unless required by applicable law or agreed to in writing, software
*  distributed under the License is distributed on an "AS IS" BASIS,
*  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*  See the License for the specific language enrstuing permissions and
*  limitations under the License.
*/
package me.zhengjie.modules.enrstu.service.impl;

import cn.hutool.core.util.ObjectUtil;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import me.zhengjie.exception.BadRequestException;
import me.zhengjie.modules.enrstu.service.dto.AdministrativeDivisionImportDto;
import me.zhengjie.modules.enrstu.service.dto.AdministrativeDivisionTemplate;
import me.zhengjie.modules.enrstu.domain.AdministrativeDivision;
import me.zhengjie.modules.enrstu.repository.AdministrativeDivisionRepository;
import me.zhengjie.modules.enrstu.service.AdministrativeDivisionService;
import me.zhengjie.modules.enrstu.service.dto.AdministrativeDivisionDto;
import me.zhengjie.modules.enrstu.service.mapstruct.AdministrativeDivisionMapper;
import me.zhengjie.modules.system.domain.User;
import me.zhengjie.modules.system.repository.UserRepository;
import me.zhengjie.modules.system.service.UserService;
import me.zhengjie.utils.SecurityUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import springfox.documentation.schema.property.field.FieldProvider;

import javax.persistence.criteria.CriteriaBuilder;
import javax.persistence.criteria.CriteriaQuery;
import javax.persistence.criteria.Predicate;
import javax.persistence.criteria.Root;
import java.lang.reflect.Field;
import java.util.HashMap;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;
/**
* @website https://eladmin.vip
* @description 服务实现
* @author yyx
* @date 2024-10-22
**/
@Slf4j
@Service(value = "administrativeDivisionServiceImpl")
@RequiredArgsConstructor
public class AdministrativeDivisionServiceImpl implements AdministrativeDivisionService{

    private final AdministrativeDivisionRepository repository;
    private final AdministrativeDivisionMapper administrativeDivisionMapper;
    private final UserRepository userRepository;
    //用与保存用户所选择的行政区;后面用于添加添加社区操作
    private static final Map<Integer,String> WAIT_SAVA;
    // 字段名与级别的映射
    private static final Map<String, Integer> FIELD_LEVEL_MAP ;
    static {
        WAIT_SAVA = new LinkedHashMap<>();
        FIELD_LEVEL_MAP = new HashMap<>();
        FIELD_LEVEL_MAP.put("province", 10);
        FIELD_LEVEL_MAP.put("prefecture", 20);
        FIELD_LEVEL_MAP.put("county", 30);
        FIELD_LEVEL_MAP.put("town", 40);
        FIELD_LEVEL_MAP.put("village", 50);
    }

    @Override
    public List<AdministrativeDivisionDto> findByDivisionLevel(Integer divisionLevel){
        return administrativeDivisionMapper.toDto(repository.findByAdministrativeDivisionLevel(divisionLevel));
    }
    @Override
    public boolean isMunicipality(String province) {
        List<AdministrativeDivision> provinceAll = repository.findAll((Root<AdministrativeDivision> root, CriteriaQuery<?> query, CriteriaBuilder cb) -> {
            Predicate divisionName = cb.like(root.get("administrativeDivisionName"), "%市");
            Predicate divisionLevel = cb.equal(root.get("administrativeDivisionLevel"), 10);
            return cb.and(divisionName, divisionLevel);
        });
        //判断是否为直辖市
        return provinceAll.stream().anyMatch(administrativeDivision -> administrativeDivision.getAdministrativeDivisionName().equals(province));
    }

    @Override
    public AdministrativeDivision findByDivisionName(String province) {
        return repository.findByAdministrativeDivisionName(province);
    }

    @Override
    public List<AdministrativeDivision> findByDivisionSign(Integer divisionSign, Integer divisionLevel) {
        return repository.findByAdministrativeDivisionSignAndAdministrativeDivisionLevel(divisionSign,divisionLevel);
    }


    @Override
    public AdministrativeDivision findByDivisionIdAndDivisionSign(Long divisionId, Integer divisionSign) {
            return repository.findByAdministrativeDivisionIdAndAdministrativeDivisionLevel(divisionId, divisionSign);
    }

    @Override
    public List<AdministrativeDivisionDto> findByIdsublevelList(Long administrativeDivisionId){

        //根据administrativeDivisionId获取对应的实体类
        AdministrativeDivision administrative = repository.findByAdministrativeDivisionId(administrativeDivisionId);
        //如果添加的administrative的等级 且行政区名称不同，证明用户重新选择查询某行政等级的子级，所以则将比以前添加好的子级进行移除
        if (WAIT_SAVA.containsKey(administrative.getAdministrativeDivisionLevel()) &&
                !ObjectUtil.equal(WAIT_SAVA.get(administrative.getAdministrativeDivisionLevel()), administrative.getAdministrativeDivisionName())){
            WAIT_SAVA.entrySet().removeIf(entry -> entry.getKey() > administrative.getAdministrativeDivisionLevel());
        }
        WAIT_SAVA.put(administrative.getAdministrativeDivisionLevel(),administrative.getAdministrativeDivisionName());
        //通过自定义jpa根据administrative的divisionSign和divisionParentId获取子级
        return administrativeDivisionMapper.toDto(repository.
                findByIdSubLevelList(administrative.getAdministrativeDivisionId(),administrative.getAdministrativeDivisionSign() ));
    }



    @Override
    public List<String> filterInvalidAdministrativeDivision(List<AdministrativeDivisionImportDto> administrativeDivisionList) {

        //临时存储遍历的省、市、县、街道、社区
        Map<String, Object> tempMap = new HashMap<>();
        return administrativeDivisionList.stream().filter(uploadContent -> {
            //判断是否为直辖市
            boolean municipality = this.isMunicipality(uploadContent.getProvince());
            User user = userRepository.getById(SecurityUtils.getCurrentUserId());
            String userName = user.getDept().getName();

            if (municipality){
                if(!uploadContent.getCounty().contains(userName)){
                    throw new BadRequestException("当前用户所在部门与导入数据中的区名称不匹配,请确认当前用户登录权限!");
                }
            }else{
                if(!uploadContent.getPrefecture().contains(userName)){
                    throw new BadRequestException("当前用户所在部门与导入数据中的市名称不匹配,请确认当前用户登录权限!");
                }
            }
            //1.如果存在就不重复查询
            //2.如果省-社有一个不存在则这条记录不能被存入数据库
            boolean flag = false;
            for (Field field : AdministrativeDivisionImportDto.class.getDeclaredFields()) {
                field.setAccessible(true);
                try {
                    //获取当前列表对象中的字段值
                    String value = (String) field.get(uploadContent);
                    //获取当前列表对象的字段名
                    String name = field.getName();
                    //判断当前对象字段名和字段是否已经存储在map集合中了
                    if (tempMap.containsKey(name)) {
                        //判断该值是否是已经查询过数据库了
                        if (tempMap.get(name).equals(value)) {
                            continue;
                        }
                    }
                    //判断根据等级和名称去快速判断行政区是否存在，如果存在，则返回true继续遍历当前列表对象，如果不存在，则返回false，整个对象将被进行过滤
                    if (repository.existsByAdministrativeDivisionLevelAndAdministrativeDivisionName(FIELD_LEVEL_MAP.get(name), value)) {
                        tempMap.put(name, value);
                        flag = true;
                        continue;
                    }
                    return flag;
                } catch (IllegalAccessException e) {
                    e.printStackTrace();
                }
            }
            return flag;
        }).map(administrativeDivision->{
            AdministrativeDivisionTemplate administrativeDivisionTemplate = new AdministrativeDivisionTemplate();
            BeanUtils.copyProperties(administrativeDivision,administrativeDivisionTemplate);
            return administrativeDivisionTemplate.toString();
        }).collect(Collectors.toList());
    }



}